// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Plane_3.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Kernel/Py_Plane_3.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================

#include <CGAL/basic.h>
#include <include/Kernels.h>

#include <boost/python.hpp>
#include <boost/cstdint.hpp>


const char* Plane_3_doc[]={
"An object h of the data type Plane_3 is an oriented plane in the three-dimensional Euclidean space.\n\
It is defined by the set of points with Cartesian coordinates (x,y,z) that satisfy the plane equation:\n\
h : a x + b y + c z + d = 0\n\
The plane splits E3 in a positive and a negative side. \n\
A point p with Cartesian coordinates (px, py, pz) is on the positive side of h,\n\
iff a px + b py +c pz + d > 0. It is on the negative side, iff a px + b py +c pz + d < 0.\n\
For more details see a C++ doc at :\n\
http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Kernel_23_ref/Class_Plane_3.html",

"\
h = Plane_3( a,b,c,d)\n\
creates a plane h defined by the equation a px + b py + c pz + d = 0. \n\
Notice that h is degenerate if a = b = c.\n\n\
h = Plane_3( 	Point_3 p,Point_3 q,Point_3 r)\n\
creates a plane h passing through the points p, q and r. \n\
The plane is oriented such that p, q and r are oriented in a positive sense \n\
(that is counterclockwise) when seen from the positive side of h. \n\
Notice that h is degenerate if the points are collinear.\n\n\
h = Plane_3( Point_3 p, Vector_3 v)\n\
introduces a plane h that passes through point p and that is orthogonal to v.\n\n\
h = Plane_3( Point_3 p, Direction_3 d)\n\
introduces a plane h that passes through point p and that has as an orthogonal direction equal to d.\n\n\
h = Plane_3( Line_3 l, Point_3 p)\n\
introduces a plane h that is defined through the three points l.point(0), l.point(1) and p.\n\n\
h = Plane_3( Ray_3 r, Point_3 p)\n\
introduces a plane h that is defined through the three points r.point(0), p.point(1) and p.\n\n\
h = Plane_3( Segment_3 s, Point_3 p)\n\
introduces a plane h that is defined through the three points s.source(), s.target() and p.",

"h.a(self) -> returns the first coefficient of h.",

"h.b(self) -> returns the second coefficient of h", 

"h.c(self) -> returns the third coefficient of h", 

"h.d(self) -> returns the fourth coefficient of h", 

"h.perpendicular_line(self,Point_3 p) -> Line_3\n\
returns the line that is perpendicular to h and that passes through point p.\n\
The line is oriented from the negative to the positive side of h.", 

"h.opposite(self) -> Plane_3\nreturns the plane with opposite orientation.", 

"h.point(self) -> Point_3\nreturns an arbitrary point on h.", 

"h.projection(self,Point_3 p) -> Point_3\nreturns the orthogonal projection of p on h.", 

"h.orthogonal_vector(self) -> Vector_3\nreturns a vector that is orthogonal to h and that is directed to the positive side of h.", 

"h.orthogonal_direction(self) -> Direction_3\nreturns the direction that is orthogonal to h and that is directed to the positive side of h. ", 

"h.base1(self) -> Vector_3\nreturns a vector orthogonal to orthogonal_vector().", 

"h.base2(self) -> Vector_3\nreturns a vector that is both orthogonal to base1(), and to orthogonal_vector(),\n\
and such that the result of orientation( point(), point() + base1(), point()+base2(), point() + orthogonal_vector() ) is positive.", 

"h.to_plane_basis(self) -> ", 

"h.to_2d(self,Point_3 p) -> Point_2\nreturns the image point of the projection of p under an affine transformation, which maps h onto the xy-plane, with the z-coordinate removed.", 

"h.to_3d(self,Point_2 p) -> Point_3\nreturns a point q, such that to_2d( to_3d( p ))  is equal to p.", 

"h.transform(self,Aff_transformation_3 t) -> Plane_3\nreturns the plane obtained by applying t on a point of h and the orthogonal direction of h.", 

"h.oriented_side(self) -> Oriented_side\nreturns either ON_ORIENTED_BOUNDARY, \n\
or the constant ON_POSITIVE_SIDE, or the constant ON_NEGATIVE_SIDE, \n\
determined by the position of p relative to the oriented plane h.", 

"h.has_on_positive_side(self,Point_3 p) -> bool", 

"h.has_on_negative_side(self,Point_3 p) -> bool", 

"h.has_on(self, Point_3 p) -> bool\n\n\
h.has_on(self, Line_3 l) -> bool", 

"h.is_degenerate(self) -> bool\nPlane h is degenerate, if the coefficients a, b, and c of the plane equation are zero."

};

template<class Plane_3>
boost::python::str py_repr_Plane_3(const Plane_3& p )
{
	using namespace boost::python;
	return str("Plane_3("+ str(p.a()) + " x + " + str(p.b()) + " y + " + str(p.c()) + " z + " + str(p.d()) + " = 0.0)" );
}

template <class kernel > 
void Py_Plane_3()
{
	typedef typename kernel::Point_3 						Point_3;
	typedef typename kernel::Segment_3 						Segment_3;
 	typedef typename kernel::Vector_3 						Vector_3;
 	typedef typename kernel::Direction_3 						Direction_3;
 	typedef typename kernel::Line_3 						Line_3;
  	typedef typename kernel::Ray_3 						        Ray_3;
 	typedef typename kernel::Plane_3 						Plane_3;
	typedef typename kernel::FT 							FT;

	using namespace boost::python;

        class_< Plane_3 >("Plane_3", Plane_3_doc[0],init<  >())
        .def(init< const Plane_3& >(Plane_3_doc[1]))
        .def(init< const Point_3&, const Point_3&, const Point_3& >())
        .def(init< const Point_3&, const Direction_3& >())
        .def(init< const Point_3&, const Vector_3& >())
        .def(init< const FT&, const FT&, const FT&, const FT& >())
        .def(init< const double&, const double&, const double&, const double& >())
        .def(init< const Line_3&, const Point_3& >())
        .def(init< const Segment_3&, const Point_3& >())
        .def(init< const Ray_3&, const Point_3& >())
#if CGAL_VERSION_NR < 1030301000
        .def("a", &Plane_3::a, by_cref(), Plane_3_doc[2])
        .def("b", &Plane_3::b, by_cref(), Plane_3_doc[3])
        .def("c", &Plane_3::c, by_cref(), Plane_3_doc[4])
        .def("d", &Plane_3::d, by_cref(), Plane_3_doc[5])
#else
        .def("a", &Plane_3::a, typename Value_or_cref< typename kernel::Compute_a_3, Plane_3 > ::type(), Plane_3_doc[2])
        .def("b", &Plane_3::b, typename Value_or_cref< typename kernel::Compute_b_3, Plane_3 > ::type(), Plane_3_doc[3])
        .def("c", &Plane_3::c, typename Value_or_cref< typename kernel::Compute_c_3, Plane_3 > ::type(), Plane_3_doc[4])
        .def("d", &Plane_3::d, typename Value_or_cref< typename kernel::Compute_d_3, Plane_3 > ::type(), Plane_3_doc[5])
#endif
        .def("perpendicular_line", &Plane_3::perpendicular_line, Plane_3_doc[6])
        .def("opposite", &Plane_3::opposite, Plane_3_doc[7])
        .def("point", &Plane_3::point, Plane_3_doc[8])
        .def("projection", &Plane_3::projection, Plane_3_doc[9])
        .def("orthogonal_vector", &Plane_3::orthogonal_vector, Plane_3_doc[10])
        .def("orthogonal_direction", &Plane_3::orthogonal_direction, Plane_3_doc[11])
        .def("base1", &Plane_3::base1, Plane_3_doc[12])
        .def("base2", &Plane_3::base2, Plane_3_doc[13])
//         .def("to_plane_basis", &Plane_3::to_plane_basis, Plane_3_doc[14])
        .def("to_2d", &Plane_3::to_2d, Plane_3_doc[15])
        .def("to_3d", &Plane_3::to_3d, Plane_3_doc[16])
        .def("transform", &Plane_3::transform, Plane_3_doc[17])
        .def("oriented_side", &Plane_3::oriented_side, Plane_3_doc[18])
        .def("has_on_positive_side", &Plane_3::has_on_positive_side, Plane_3_doc[19])
        .def("has_on_negative_side", &Plane_3::has_on_negative_side, Plane_3_doc[20])
        .def("has_on", (bool (Plane_3::*)(const Point_3&) const)&Plane_3::has_on, Plane_3_doc[21])
        .def("has_on", (bool (Plane_3::*)(const Line_3&) const)&Plane_3::has_on)
        .def("is_degenerate", &Plane_3::is_degenerate, Plane_3_doc[22])
	.def("__repr__", &py_repr_Plane_3<Plane_3>)
       	.def( self == self )
        .def( self != self )
    ;
}


void export_Plane_3()
{
	Py_Plane_3<K>();
}
